#include "pch.h"
#include "GlfwWindow.h"
#include <GLFW/glfw3.h>
#include "Common.h"

using namespace hiveFX;

CGlfwWindow* CGlfwWindow::createWindow(const std::string& vConfigFilePath)
{
	std::ifstream File(vConfigFilePath);
	nlohmann::json Config = nlohmann::json::parse(File);
	const int Width = Config.contains("width") ? std::max(1, static_cast<int>(Config["width"])) : 800;
	const int Height = Config.contains("height") ? std::max(1, static_cast<int>(Config["height"])) : 600;
	const int GlMajorVersion = Config.contains("gl_major_version") ? std::max(0, static_cast<int>(Config["gl_major_version"])) : 4;
	const int GlMinorVersion = Config.contains("gl_minor_version") ? std::max(0, static_cast<int>(Config["gl_minor_version"])) : 6;
	const bool EnableImGui = Config.contains("enable_imgui") ? static_cast<bool>(Config["enable_imgui"]) : true;
	const std::string Title = Config.contains("title") ? static_cast<std::string>(Config["title"]) : "HiveFX";

	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GlMajorVersion);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GlMinorVersion);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	GLFWwindow* pWindow = glfwCreateWindow(Width, Height, Title.c_str(), nullptr, nullptr);
	if (pWindow == nullptr)
	{
		glfwTerminate();
		LOG_ERROR("CGlfwWindow", "Failed to create glfw window");
		return nullptr;
	}
	glfwMakeContextCurrent(pWindow);
	if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
	{
		LOG_ERROR("CGlfwWindow", "failed to initialize glad");
		return nullptr;
	}

	if (EnableImGui)
	{
		// Setup Dear ImGui context
		IMGUI_CHECKVERSION();
		ImGui::CreateContext();
		ImGuiIO& Io = ImGui::GetIO();
		Io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
		Io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
		//io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;         // IF using Docking Branch

		// Setup Platform/Renderer backends
		ImGui_ImplGlfw_InitForOpenGL(pWindow, true);          // Second param install_callback=true will install GLFW callbacks and chain to existing ones.
		ImGui_ImplOpenGL3_Init();
	}

	return new CGlfwWindow(pWindow, EnableImGui);
}

CGlfwWindow::~CGlfwWindow()
{
	if (m_EnableImGui)
	{
		ImGui_ImplOpenGL3_Shutdown();
		ImGui_ImplGlfw_Shutdown();
		ImGui::DestroyContext();
	}

	glfwDestroyWindow(m_pWindow);
	m_pWindow = nullptr;
	glfwTerminate();
}

std::pair<int, int> CGlfwWindow::getExtent() const
{
	int Width, Height;
	glfwGetFramebufferSize(m_pWindow, &Width, &Height);
	return { Width, Height };
}

bool CGlfwWindow::shouldClose() const
{
	return glfwWindowShouldClose(m_pWindow);
}

void CGlfwWindow::swapBuffers() const
{
	glfwSwapBuffers(m_pWindow);
}

void CGlfwWindow::pollEvents()
{
	glfwPollEvents();
}

void hiveFX::CGlfwWindow::beginFrame()
{
	// (Your code calls glfwPollEvents())
	// ...
	// Start the Dear ImGui frame
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();
	//ImGui::ShowDemoWindow(); // Show demo window! :)
}

void hiveFX::CGlfwWindow::endFrame()
{
	// Rendering
	// (Your code clears your framebuffer, renders your other stuff etc.)
	ImGui::Render();
	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
	// (Your code calls glfwSwapBuffers() etc.)
}

bool hiveFX::CGlfwWindow::wantCaptureMouse()
{
	const ImGuiIO& Io = ImGui::GetIO();
	return Io.WantCaptureMouse;
}

bool hiveFX::CGlfwWindow::wantCaptureKeyboard()
{
	const ImGuiIO& Io = ImGui::GetIO();
	return Io.WantCaptureKeyboard;
}

CGlfwWindow::CGlfwWindow(GLFWwindow* vWindow, bool vEnableImGui) :m_pWindow(vWindow), m_EnableImGui(vEnableImGui)
{
	glfwSetWindowUserPointer(m_pWindow, this);
	//__registerCallbacks();
}
